#!/usr/bin/env python
# encoding: utf-8
"""
window.py

Created by daspork on 2012-04-21.
Copyright (c) 2012 Knuckledragger Games. All rights reserved.
"""

import sys
import os

from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *

class Window(object):
    """
    This is the base window/context class. It provides an interface for the
    state machine etc
    """
    def __init__(self, windowRect, windowTitle):
        self._InitGLUT(windowRect, windowTitle)
        ## The game states pushed to the window
        self._states = []
        ## The last time from the loop for calculating the delta
        self._lastTime = 0
        ## FPS counter
        self._fps_time_count = 0
        self._fps_count = 0
        self._last_fps = 0
        self._dt = 0


    def _InitGLUT(self, windowRect, windowTitle):
        """
            Initialize GLUT
        """
        ## Initialize GLUT
        glutInit()
        
        ## Setup the window size
        glutInitWindowSize (windowRect[2], windowRect[3])
        
        ## Set the glut flags
        glutInitDisplayMode ( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH)
        
        ## Create the window
        glutCreateWindow (windowTitle)
        
        ## Setup the GLUT callbacks
        glutDisplayFunc(self._display)
        glutReshapeFunc(self._reshape)
        glutIdleFunc(self._idle)
        glutKeyboardFunc(self._keyboardDown)
        glutKeyboardUpFunc(self._keyboardUp)
        #glutMouseFunc(self._mouseButton)
        #glutMotionFunc(self._mouseMotion)
        #glutEntryFunc()
        #glutJoystickFunc()
        #glutSpecialFunc()
        #glutSpecialUpFunc()
        #glutVisibilityFunc()
        #glutWindowStatusFunc()
        
        ## Setup some OpenGL States
        glEnable(GL_DEPTH_TEST)

        

    ############################################################################
    ## Glut Callbacks                                                         ##
    ############################################################################
    
    def _reshape(self, width, height):
        """
            Call the reshape callback on the top state
        """
        ## Check empty states.
        self._checkStatesEmpty()
        ## Fire the reshape callback
        self._states[0].doReshape(width, height)
        

    def _display(self):
        """
            Call the display callback on the top state
        """
        ## Check empty states.
        self._checkStatesEmpty()
        ## Fire the display callback on the top state.
        self._states[0].doDisplay(self.DeltaTime)


    def _idle(self):
        """
            Call the idle callback on the top state
        """
        ## Check empty states.
        self._checkStatesEmpty()
        
        ## Do time delta comp
        timeSinceStart = glutGet(GLUT_ELAPSED_TIME);
        self._dt = (timeSinceStart -  self._lastTime) * 0.001
        self._lastTime = timeSinceStart
        
        
        ## Do FPS calculation
        self._fps_time_count += self.DeltaTime
        self._fps_count += 1
        if self._fps_time_count > 1:
            self._last_fps = self._fps_count
            self._fps_count = 0
            self._fps_time_count = 0
            
        ## Fire the display callback on the top state.
        self._states[0].doIdle(self.DeltaTime)
        
        
    def _keyboardDown(self, key, x, y):
        """
            Call the keydown callback on the top state
        """
        ## Check empty states.
        self._checkStatesEmpty()
        ## Fire the display callback on the top state.
        self._states[0].doKeyboardDown(key, x, y)


    def _keyboardUp(self, key, x, y):
        """
            Call the keyup callback on the top state
        """
        ## Check empty states.
        self._checkStatesEmpty()
        ## Fire the display callback on the top state.
        self._states[0].doKeyboardUp(key, x, y)
        
        
    def _mouseButton(self):
        pass
    
    
    def _mouseMotion(self):
        pass
    
    
    ############################################################################
    ## State Manipulation                                                     ##
    ############################################################################
    
    def Push(self, state):
        """
            Push the state to the top of the stack.
        """
        self._states.insert(0, state)
        state.doInit()


    def Pop(self):
        """
            Pop the top state off the stack
        """
        print "Window::Popping Top State"
        self._checkStatesEmpty()
        top = self._states[0]
        self._states.remove(top)
    

    def _checkStatesEmpty(self):
        if self._states != []:
            return True
        else:
            print "Window: There are no states on the stack!"
            sys.exit(0)
        

    ############################################################################
    ## Window/Context state changes                                           ##
    ############################################################################
    
    def Clear(self):
        """
            Clear the OpenGL context
        """
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        
        
    def Swap(self):
        """
            Swap the back buffer for the front
        """
        glutSwapBuffers()
        
        
    def Damage(self):
        glutPostRedisplay()
    

    def Run(self):
        glutMainLoop();

    ############################################################################
    ## Window/Context Properties                                              ##
    ############################################################################   

    @property
    def Width(self):
        """
            The width of the window
        """
        return glutGet(GLUT_WINDOW_WIDTH)
    
    
    @property
    def Height(self):
        """
            The height of the window
        """
        return glutGet(GLUT_WINDOW_HEIGHT)
        
        
    @property    
    def DeltaTime(self):
        """
            Get the delta time of since the last loop
        """
        return self._dt 


    @property
    def Fps(self):
        return self._last_fps